﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qing.Lang {

    public enum CtxTp {
        Default,
        Temp,
    }


    /*
     * 语境Context
     * 本质上是一个键为字符串,值为Expr的Map
     * 可以理解为根据变量名存储变量的表
     * 语境为层级关系,father属性存储上一级语境
     * 所有对表达式的求解都在语境中执行
     * 对象本质上也是一个语境,所以Obj继承了Ctx
     */
    public class Ctx {

        public Dictionary<string, Expr> Map { get; set; } //存储变量的表

        public Ctx? Father; //上级语境

        public CtxTp Tp = CtxTp.Default;

        public Ctx(CtxTp tp = CtxTp.Default) {
            Map = new Dictionary<string, Expr>();
            Father = null;
            Tp = tp;
        }

        public Ctx(Ctx? f, CtxTp tp = CtxTp.Default) {
            Map = new Dictionary<string, Expr>();
            Father = f;
            Tp = tp;
        }

        public void SetFather(Ctx? f) {
            Father = f;
        }

        /*在当前语境中绑定变量*/
        public void PutNow(string k, Expr v) {
            Map[k] = v;
        }

        /*
         * 绑定变量
         * 先逐级向上查找变量是否已绑定
         * 如果已绑定，则更新绑定
         * 如果未绑定，说明没变量未定义
         * 到LibCtx的下级进行绑定
         */
        public void Put(string k, Expr v) {
            Ctx curr = this;
            /*逐级向上查找*/
            while (!curr.Map.ContainsKey(k) && curr.Father != null) {
                /*
                 * 不能修改LibCtx中的绑定关系
                 * 如果发现上级已经是LibCtx
                 * 那么直接再本级绑定
                 * 相当于是全局变量
                 */
                if (curr.Father.Father == null) {
                    curr.Map[k] = v;
                    return;
                }
                curr = curr.Father;
            }
            curr.Map[k] = v;
            return;
        }

        /*在当前语境根据变量名获取变量值*/
        public Expr GetNow(string k) {
            Expr v = Map.GetValueOrDefault(k, new Expr(TP.None, 0));
            /*if (v.tp == TP.native && this is Obj) {
                v.Native().obj = (Obj)this;
            }*/
            return v;
        }

        /*
         * 根据变量名获取变量
         * 先逐级向上查找变量是否已绑定
         * 如果已绑定，返回变量值
         * 如果未绑定，返回空
         */
        public Expr Get(string k) {
            Ctx curr = this;
            while (!curr.Map.ContainsKey(k) && curr.Father != null) {
                curr = curr.Father;
            }
            Expr v = curr.Map.GetValueOrDefault(k, new Expr(TP.None, 0));
/*            if (v.tp == TP.native && curr is Obj) {
                v.Native().obj = (Obj)curr;
            }*/
            return v;
        }

        /*在当前语境删除绑定*/
        public Expr RemoveNow(string k) {
            if (Map.ContainsKey(k)) {
                Map.Remove(k);
                return new Expr(TP.Bool, true);
            } else {
                return new Expr(TP.Bool, false);
            }
        }


        /*
         * 删除绑定
         * 先逐级向上查找变量是否已绑定
         * 如果已绑定，删除绑定，返回真
         * 如果始终未发现绑定，返回假
         */
        public Expr Remove(string k) {
            Ctx? ctx = this;
            while (ctx != null) {
                if (ctx.Map.ContainsKey(k)) {
                    if (ctx.Father == null) {
                        return new Expr(TP.Bool, false);
                    }
                    Map.Remove(k);
                    return new Expr(TP.Bool, true);
                }

                ctx = ctx.Father;

            }
            return new Expr(TP.Bool, false);
        }

        /*复制一个语境*/
        public Ctx Dup() {
            Ctx ctx = new Ctx(Tp);
            ctx.Father = Father;
            foreach (var k in Map.Keys) {
                ctx.Map[k] = Map[k].Dup();
            }
            return ctx;
        }

        /*深拷贝一个语境*/
        public Ctx Clone() {
            Ctx ctx = new Ctx(Tp);
            ctx.Father = Father;
            foreach (var k in Map.Keys) {
                ctx.Map[k] = Map[k].Clone();
            }
            return ctx;
        }

    }
}
